package com.zx.auth.block.repository.custom.impl;

import com.zx.auth.block.modle.OAuth2AuthorizationConsent;
import com.zx.auth.block.param.OAuth2AuthorizationConsentParam;
import com.zx.auth.block.repository.custom.OAuth2AuthorizationConsentCustomRepository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * <p>
 * description: OAuth2授权同意自定义仓库实现 <br>
 * create: 2025-11-13 10:45
 * </p>
 *
 * @author
 */
@Repository
public class OAuth2AuthorizationConsentRepositoryImpl implements OAuth2AuthorizationConsentCustomRepository {

    // 注入EntityManager实例，用于执行JPA查询
    private final EntityManager entityManager;

    @Autowired
    public OAuth2AuthorizationConsentRepositoryImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    /**
     * 根据条件分页查询授权同意
     *
     * @param consentParam 查询条件
     * @param pageable     分页对象
     * @param tenantId     租户ID
     * @return 授权同意分页结果
     */
    @Override
    public Page<OAuth2AuthorizationConsent> findAuthorizationConsentsByPage(OAuth2AuthorizationConsentParam consentParam, Pageable pageable, String tenantId) {
        // 获取CriteriaBuilder实例，用于构建查询
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();

        // 创建一个返回OAuth2AuthorizationConsent类型的CriteriaQuery
        CriteriaQuery<OAuth2AuthorizationConsent> criteriaQuery = cb.createQuery(OAuth2AuthorizationConsent.class);

        // 从OAuth2AuthorizationConsent实体类创建一个根节点，用于后续的查询构建
        Root<OAuth2AuthorizationConsent> consentRoot = criteriaQuery.from(OAuth2AuthorizationConsent.class);

        // 构建查询条件
        Predicate[] predicates = buildPredicates(consentRoot, consentParam, cb, tenantId);

        // 设置查询的WHERE子句，并添加默认排序
        criteriaQuery.where(predicates).orderBy(cb.desc(consentRoot.get("registeredClientId")));

        // 创建一个TypedQuery，用于执行具体的查询
        TypedQuery<OAuth2AuthorizationConsent> typedQuery = entityManager.createQuery(criteriaQuery);

        // 设置查询的起始位置和结果数量限制
        typedQuery.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
        typedQuery.setMaxResults(pageable.getPageSize());

        // 执行查询并获取结果列表
        List<OAuth2AuthorizationConsent> content = typedQuery.getResultList();

        // 计算总记录数
        Long total = countByAuthorizationConsent(consentParam, tenantId);

        // 创建并返回PageImpl对象，封装分页结果
        return new PageImpl<>(content, pageable, total);
    }

    /**
     * 根据注册客户端ID、主体名称和租户ID查找授权同意信息
     *
     * @param registeredClientId 注册客户端ID
     * @param principalName      主体名称
     * @param tenantId           租户ID
     * @return 授权同意信息
     */
    @Override
    public Optional<OAuth2AuthorizationConsent> findByRegisteredClientIdAndPrincipalNameAndTenantId(String registeredClientId, String principalName, String tenantId) {
        // 获取CriteriaBuilder实例，用于构建查询
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();

        // 创建一个返回OAuth2AuthorizationConsent类型的CriteriaQuery
        CriteriaQuery<OAuth2AuthorizationConsent> criteriaQuery = cb.createQuery(OAuth2AuthorizationConsent.class);

        // 从OAuth2AuthorizationConsent实体类创建一个根节点，用于后续的查询构建
        Root<OAuth2AuthorizationConsent> consentRoot = criteriaQuery.from(OAuth2AuthorizationConsent.class);

        // 构建查询条件
        List<Predicate> predicates = new ArrayList<>();
        predicates.add(cb.equal(consentRoot.get("registeredClientId"), registeredClientId));
        predicates.add(cb.equal(consentRoot.get("principalName"), principalName));
        predicates.add(cb.equal(consentRoot.get("tenantId"), tenantId));

        // 设置查询的WHERE子句
        criteriaQuery.where(predicates.toArray(new Predicate[0]));

        // 创建一个TypedQuery，用于执行具体的查询
        TypedQuery<OAuth2AuthorizationConsent> typedQuery = entityManager.createQuery(criteriaQuery);

        // 执行查询并返回结果
        List<OAuth2AuthorizationConsent> result = typedQuery.getResultList();
        return result.isEmpty() ? Optional.empty() : Optional.of(result.get(0));
    }

    /**
     * 根据条件查询授权同意数量
     *
     * @param consentParam 查询条件
     * @param tenantId     租户ID
     * @return 记录总数
     */
    private Long countByAuthorizationConsent(OAuth2AuthorizationConsentParam consentParam, String tenantId) {
        // 获取CriteriaBuilder实例，用于构建查询
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();

        // 创建一个返回Long类型的CriteriaQuery
        CriteriaQuery<Long> criteriaQuery = cb.createQuery(Long.class);

        // 从OAuth2AuthorizationConsent实体类创建一个根节点，用于后续的查询构建
        Root<OAuth2AuthorizationConsent> consentRoot = criteriaQuery.from(OAuth2AuthorizationConsent.class);

        // 构建查询条件
        Predicate[] predicates = buildPredicates(consentRoot, consentParam, cb, tenantId);

        // 设置查询的SELECT子句，统计满足条件的记录数
        criteriaQuery.select(cb.count(consentRoot)).where(predicates);

        // 创建一个TypedQuery，用于执行具体的查询
        TypedQuery<Long> typedQuery = entityManager.createQuery(criteriaQuery);

        // 执行查询并返回结果
        return typedQuery.getSingleResult();
    }

    /**
     * 构建查询条件
     *
     * @param consentRoot  根节点
     * @param consentParam 查询条件
     * @param cb           CriteriaBuilder实例
     * @param tenantId     租户ID
     * @return 查询条件数组
     */
    private Predicate[] buildPredicates(Root<OAuth2AuthorizationConsent> consentRoot, OAuth2AuthorizationConsentParam consentParam, CriteriaBuilder cb, String tenantId) {
        // 创建一个列表来存储查询条件
        List<Predicate> predicates = new ArrayList<>();

        // 如果查询条件的注册客户端ID不为空且非空字符串，则添加一个等于条件
        if (consentParam.getRegisteredClientId() != null && !consentParam.getRegisteredClientId().trim().isEmpty()) {
            predicates.add(cb.equal(consentRoot.get("registeredClientId"), consentParam.getRegisteredClientId()));
        }

        // 如果查询条件的主体名称不为空且非空字符串，则添加一个等于条件
        if (consentParam.getPrincipalName() != null && !consentParam.getPrincipalName().trim().isEmpty()) {
            predicates.add(cb.equal(consentRoot.get("principalName"), consentParam.getPrincipalName()));
        }

        // 添加租户ID条件
        predicates.add(cb.equal(consentRoot.get("tenantId"), tenantId));

        // 将列表转换为数组并返回
        return predicates.toArray(new Predicate[0]);
    }
}